﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.Samples.ServiceHosting.StorageClient;
using Ciripescu_WebRole.Entities;
using Ciripescu_WebRole.BL;
using Ciripescu_WebRole;
using System.Data.Services.Client;

namespace Ciripescu_WebRole.BL
{
    public class CiripCacheManager
    {
        public static int NbOfCiripsPerPage = Ciripescu_WebRole.Properties.Settings.Default.NbOfCiripsPerPage;
        #region Public Methods

        public CiripCacheManager()
        {
            m_svcContext             = new MyServiceContext();
            m_svcContext.RetryPolicy = RetryPolicies.RetryN(3, TimeSpan.FromSeconds(1));
        }

        /// <summary>
        /// Executa un query cu toate retry-urile si continuation token-urile necesare
        /// </summary>
        /// <param name="q"></param>
        /// <returns></returns>
        public IEnumerable<CiripCache> DoQuery(IQueryable<CiripCache> q)
        {
            TableStorageDataServiceQuery<CiripCache> query = new TableStorageDataServiceQuery<CiripCache>(q as DataServiceQuery<CiripCache>);
            IEnumerable<CiripCache> queryResults           = query.ExecuteAllWithRetries();            
            return queryResults;
        }

        public IEnumerable<CiripCache> DoQuery(IQueryable<CiripCache> q, int count)
        {
            //TableStorageDataServiceQuery<CiripCache> query = new TableStorageDataServiceQuery<CiripCache>(q as DataServiceQuery<CiripCache>);
            IEnumerable<CiripCache> queryResults = q.Take(count);
            return queryResults;
        }

        public CiripCache GetSingleCiripCache(string userName,string rowKey)
        {
            try
            {
                return (DoQuery(from c in m_svcContext.CiripCache where c.From == userName && c.RowKey == rowKey select c)).Single();
            }
            catch (InvalidOperationException)
            {
                // no items to return
                return null;
            }
            catch (Exception e)
            {
                // oare mai de ce se logheaza aici si mai sus nu? Las asa ca nu stiu care ii faza....
                Utils.WriteLog(EventLogName.Error, e.ToString());
                return null;
            }
        }

        public List<CiripCache> GetAllItems()
        {
            //return CiripCacheListToCiripList(DoQuery(from c in m_svcContext.CiripCache select c).ToList());
            return DoQuery(from c in m_svcContext.CiripCache select c).ToList();
        }

        public IEnumerable<CiripCache> GetAllItems(string startFromRowKey)
        {
            //return CiripCacheListToCiripList(DoQuery(from c in m_svcContext.CiripCache where c.RowKey.CompareTo(startFromRowKey) > 0 select c).ToList());
            return DoQuery(from c in m_svcContext.CiripCache where c.RowKey.CompareTo(startFromRowKey) > 0 select c).ToList();
        }

        // faptul ca intro parte returnez Cirip si in alta CiripCache o fost una din deciizile proaste luate la o ora tarzie (sau foarte devreme :))
        // acuma e multe de schimbat si las asa. Have fun la debugging :P
        public List<Cirip> GetAllItems(int currentPage)
        {
            var results = from c in m_svcContext.CiripCache select c;

            if (currentPage <= 0)
                return CiripCacheListToCiripList(DoQuery(results));

            List<CiripCache> ret = null;
            if (currentPage*NbOfCiripsPerPage<950)
                ret = DoQuery(results, currentPage * NbOfCiripsPerPage+2).ToList();
            else ret = DoQuery(results).ToList();

            // verifica daca exista pagina
            if (ret.Count > (currentPage - 1) * NbOfCiripsPerPage)
            {
                if (NbOfCiripsPerPage * currentPage > ret.Count) // este ultima pagina
                    return CiripCacheListToCiripList(ret.GetRange(NbOfCiripsPerPage * (currentPage - 1), ret.Count - NbOfCiripsPerPage * (currentPage - 1)));
                else // pagina oarecare
                    return CiripCacheListToCiripList(ret.GetRange(NbOfCiripsPerPage * (currentPage - 1), NbOfCiripsPerPage));
            }
            
            else return new List<Cirip>();// daca s-a cerut pagina care nu exista nu intoarce nimic
        }
        

        /// <summary>
        /// Gets the total number of CiripCaches for a single user.
        /// </summary>
        /// <param name="userName"></param>
        /// <returns></returns>
        public int GetNrOfCiripCaches(string userName)
        {
            var results = from c in m_svcContext.CiripCache where c.From == userName select c;
            IEnumerable<CiripCache> list = DoQuery(results);
            return list.Count<CiripCache>();
        }

 
        public void Delete(CiripCache itemToDelete)
        {
            m_svcContext.DeleteObject(itemToDelete);
            m_svcContext.SaveChanges();
        }

        public void DeleteWithoutQ(CiripCache itemToDelete)
        {
            m_svcContext.AttachTo(m_svcContext.CiripCacheTableName, itemToDelete, "*");
            Delete(itemToDelete);
        }

        public void Commit()
        {
            m_svcContext.SaveChanges();
        }

        public void DeleteWithNoCommit(CiripCache itemToDelete)
        {
            m_svcContext.DeleteObject(itemToDelete);
        }

        /// <summary>
        /// Updates an existing item from the tables.
        /// </summary>
        /// <param name="item"></param>
        public void Save(CiripCache item)
        {
            m_svcContext.UpdateObject(item);
            m_svcContext.SaveChanges();
        }

        /// <summary>
        /// Insert a new item in the tables.
        /// </summary>
        /// <param name="newItem"></param>
        public void Insert(CiripCache newItem)
        {
            m_svcContext.AddObject(m_svcContext.CiripCacheTableName, newItem);
            m_svcContext.SaveChanges();
        }

        public Cirip CiripCacheToCirip(CiripCache m)
        {            
            Cirip c = null;
            c = new Cirip(m.From, m.Content, m.InReplyToUser, m.InReplyToId);
            c.RowKey = m.RowKey; // the generated rowkey will have a timestamp with this very second, we need the original RowKey
            c.Timestamp = m.Timestamp;
            c.TimePosted = m.TimePosted;
            return c;
        }

        public List<Cirip> CiripCacheListToCiripList(IEnumerable<CiripCache> mlist)
        {
            List<Cirip> ret = new List<Cirip>();
            foreach (CiripCache m in mlist)
                ret.Add(CiripCacheToCirip(m));
            return ret;
        }

        #endregion 

        #region Private Methods

        private MyServiceContext m_svcContext = null;
        
        #endregion
    }
}
